#include "data_cache.h"

#include "eventloop.h"
#include "adr_trigger.h"
#include "data_record.h"
#include "public_define.h"
#include "dc_util.h"
#include "json/json.h"
#include "antianaphylaxis_queue.h"
#include "encode_srv.pb.h"
#include "signal_collect.h"
#include "manager_file.h"
#include "fileReupload.h"
#include "special_trigger.h"
#include "TcpClientInstance.h"
#include "calibration_file.h"
#include "soaEnginerringModel.h"
#include <unordered_map>
#include "map_collect.h"
#include <malloc.h>
#include "tool.h"

#define CODEC_PROBE_H265_I_FRAME(data) (0x0 == ((char *)data)[0] && 0x0 == ((char *)data)[1] && 0x0 == ((char *)data)[2] && 0x1 == ((char *)data)[3] && 0x40 == ((char *)data)[4])
using namespace DcAdr;

bool IsCerFileExist()
{
    string cerPath = global_data::g_http_ca_path + global_data::g_client_cert;
    if (0 == access(cerPath.c_str(), F_OK))
    {
        return true;
    }
    static bool printNoCer = true;
    if (printNoCer)
    {
        printNoCer = false;
        Log_Info("error;have no cer file;in {}", cerPath);
    }
    return false;
}
DataCache::DataCache()
{
    Log_Info("run timer...");
    m_timer = new Timer();
    m_timer->Start(200, std::bind(&DataCache::timeOut, this));
    auto func = [this]() {
        while (true) {

            //EventLoop::getInstance()[E_InDataDealThread]
            if (!EventLoop::getInstance(ThreadType::E_InDataDealThread)->isRunning()) {
                Log_Info("Out of E_InDataDealThread thread...");
                break;
            }

            std::vector<ProtoData> data_list;
            {
                std::lock_guard<std::mutex> lk(m_receiveDataMutex);
                data_list.swap(m_receiveData);
            }
            for (const auto& data: data_list) {
                processData(data);
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
    };
    appendEvent(ThreadType::E_InDataDealThread, func);
}

DataCache::~DataCache()
{
}

#if 0
void DataCache::doSBtest()
{
    static bool bfill0 = true;

    std::fstream i("/ota/sbtest.txt");
    if (!i)
    {
        Log_ERROR("get local file error!");
        return;
    }
    std::stringstream ss;
    ss << i.rdbuf();
    std::string desenListStr = ss.str();
    i.close();

    if (!desenListStr.compare("1"))
    {
        if (!bfill0)
        {
            return;
        }

        TriggerEventInfo trigger;
        trigger.taskId = 12344;
        Log_Info("zjs_tmp_0105;44");
        TcpClientInstance::getInstance().init("/ota/2024-01-16_14-10-36_2_IT088.dat", trigger);//zjs_tmp_shaobing
        bfill0 = false;
    }
    else
    {
        bfill0 = true;
        Log_ERROR("desenListStr:{}", desenListStr);
    }

}

void DataCache::doNeiCunTest()
{
#if 1
    Log_Info("[CollectConfig] [init] USE_LOCAL_CONFIG");
    std::string ret = "";
    const char *path = global_data::g_config_path.c_str();
    ifstream in(path);
    if (in)
    {
        Log_Info("USE_LOCAL_CONFIG ok");
        stringstream buffer;
        buffer << in.rdbuf();
        ret = buffer.str();
        in.close();
    }
    else
    {
        // ModifyDiagnosisSts(8);
    }
    Log_Info("capacity: {}  size: {}", ret.capacity(), ret.size());
    Log_Info("USE_CONFIG 11: {}", ret);
#else
    std::string ret;
    CommonOprSystem::readFileAllOnce(global_data::g_config_path, ret);
    Log_Info("USE_CONFIG 22: {}", ret);
#endif
}

void DataCache::doNeiCunTest()
{
    static bool isin = false;

    if (isin)
    {
        return;
    }

    isin = true;
    
    std::unordered_map<std::string, int> myMap;
    myMap["apple"] = 5;
    myMap["banana"] = 3;
    myMap["orange"] = 7;

    // 遍历所有键值对
    for (const auto& pair : myMap) 
    {
        Log_Info("first:{} send:{}", pair. first, pair. second);
    }

    std::string keyToFind = "aaa";
    if (myMap.find(keyToFind) != myMap.end())
    {
        Log_Info("keyToFind:{}  value:{}", keyToFind, myMap[keyToFind]);
    }
    else
    {
        Log_Info("keyToFind:{}  not found", keyToFind);
    }

    myMap.erase(keyToFind);
    Log_Info("myMap size:{} ", myMap.size());


    // 遍历所有键值对
    for (const auto& pair : myMap) 
    {
        Log_Info("first:{} send:{}", pair. first, pair. second);
    }
}
#endif

void DataCache::timeOut()
{
    if (!global_data::g_collect_config_buf.empty()) // 获取到的配置不是空，加构造SignalCollect类，读信号采集配置，做信号上云
    {
        // 发送信号快照上云
        SignalCollect::getInstance().sendSignalShot();
    }

    if (m_lastInterlTime == 1000)
    {
        // doSBtest();//zjs_tmp_shaobing
        // doNeiCunTest();//zjs_tmp_test;
        
        Log_Info("global_data::g_work_status: {}", global_data::g_work_status);
        if (!m_dataCache.empty())
        { // 增加非空判断
            Log_Info("[DataCache] m_dataCache First frame: Time:{},m_dataCache end frame: Time:{},m_dataCache intervening time:{},m_dataCache size:{}",
                     to_string(m_dataCache.begin()->first),
                     to_string(m_dataCache.rbegin()->first),
                     to_string(m_dataCache.rbegin()->first - m_dataCache.begin()->first),m_dataCache.size());
        }

        // 处理脱敏视频
        AntianaphylaxisQueue::getInstance().dealQueue();

        // 检查事件是否结束
        checkTriggerEventEnd();
        // 检查数据是否过期
        checkDataTimeValid();

        static int prinA = 0;
        if (prinA % 10 == 0 )//每10s打印
        {
            prinA = 0;
            Log_Info("data size: {}", m_dataCache.size());
        }
        prinA++;

        m_lastInterlTime = 0;
    }
    if (m_lastReuploadTime == 5000) // 5秒一次
    {
        // 文件补传
        FileReupload::getInstance().timerReupload();
        
        ManagerFile::getInstance().CheckBA692CommitEnd();

        m_lastReuploadTime = 0;
    }

    if (m_getAndrEnvirTime == 60000)//1分钟获取一次环境熟悉
    {
        m_component->getAndrEnvirAgain();
        //getAndrEnvirAgain();
        m_getAndrEnvirTime = 0;
    }
    if(m_malloc_trim ==5* 60* 1000)
    {
        malloc_trim(0);
        m_malloc_trim=0;
    }
    m_malloc_trim +=200;
    m_lastInterlTime += 200;
    m_lastReuploadTime += 200;
    m_getAndrEnvirTime += 200;
}

void DataCache::setPublishHandle(adr_component *component)
{
    m_component = component;
}

DataCache &DataCache::getInstance()
{
    static DataCache cache;
    return cache;
}

void DataCache::checkPictureDataTimeValid(const std::string &topic, const ProtoData &data)
{

    (void)topic;

    // 如果是图片topic，缓存机制进行特殊处理
    if ((*data.topic).find("encode_srv-EncodeSrv.EncodeJpeg-CAM") != std::string::npos)
    {
        double currTime = Util::getMsTime();

        std::lock_guard<std::mutex> lk(m_mutex);

        // Log_Info("enter checkPictureDataTimeValid topic: {}", *data.topic);
        // Log_Info("pictureDataCacheFirst.time: {}", m_pictureDataCacheMap[*data.topic].pictureDataCacheFirst.time);
        //  第三帧一直存储最新的一帧数据,一直更新
        m_pictureDataCacheMap[*data.topic].pictureDataCacheThird.time = currTime;
        m_pictureDataCacheMap[*data.topic].pictureDataCacheThird.data = data;
        if (CompareValueIsZero(m_pictureDataCacheMap[*data.topic].pictureDataCacheFirst.time) == true)
        {
            m_pictureDataCacheMap[*data.topic].pictureDataCacheFirst.time = currTime;
            m_pictureDataCacheMap[*data.topic].pictureDataCacheFirst.data = data;
            // Log_Info("first time: {}", currTime);
        }
        if ((CompareValueIsZero(m_pictureDataCacheMap[*data.topic].pictureDataCacheSecond.time) == true)
             && ((currTime - m_pictureDataCacheMap[*data.topic].pictureDataCacheFirst.time) >= 5000))
        {
            m_pictureDataCacheMap[*data.topic].pictureDataCacheSecond.time = currTime;
            m_pictureDataCacheMap[*data.topic].pictureDataCacheSecond.data = data;
            // Log_Info("second time: {}", currTime);
        }
        // 如果超过5秒就更新
        if ((CompareValueIsZero(m_pictureDataCacheMap[*data.topic].pictureDataCacheSecond.time) == false)
             && ((currTime - m_pictureDataCacheMap[*data.topic].pictureDataCacheSecond.time) >= 5000))
        {
            m_pictureDataCacheMap[*data.topic].pictureDataCacheFirst.time = m_pictureDataCacheMap[*data.topic].pictureDataCacheSecond.time;
            m_pictureDataCacheMap[*data.topic].pictureDataCacheFirst.data = m_pictureDataCacheMap[*data.topic].pictureDataCacheSecond.data;
            // Log_Info("update first time: {}", m_pictureDataCacheMap[*data.topic].pictureDataCacheFirst.time);
            m_pictureDataCacheMap[*data.topic].pictureDataCacheSecond.time = currTime;
            m_pictureDataCacheMap[*data.topic].pictureDataCacheSecond.data = data;
            // Log_Info("update second time: {}", m_pictureDataCacheMap[*data.topic].pictureDataCacheSecond.time);
        }
    }
}

void DataCache::checkDataTimeValid()
{
    std::lock_guard<std::mutex> lk(m_mutex);

    double currTime = Util::getMsTime();
    double dataTime = 0.0;

    for (auto beg = m_dataCache.begin(); beg != m_dataCache.end();)
    {
        dataTime = beg->first;
        ProtoData data = beg->second;
        ProtoValidTime pvt = getTopicDataInvildTime(*data.topic);
        double validTime = pvt.beforeTime; // 去掉1秒数据冗余，降低内存消耗
        // 当前时间大于此条数据的有效时间 或 当前时间发送了跳变，只保留跳变时刻1s内的数据
        if ((currTime - dataTime > validTime) || (currTime - dataTime < -1000))
        {
            m_dataCache.erase(beg++);
        }
        else
        {
            ++beg;
            break;
        }
    }

    // 限制map大小
    if (m_dataCache.size() > m_maxFrame)
    {
        // ModifyDiagnosisSts(2);
        uint32_t toDelet = m_dataCache.size() - m_maxFrame;
        Log_Warn("data size > max buffer size; to delet {}", toDelet);

        uint32_t i = 0;
        for (auto beg = m_dataCache.begin(); beg != m_dataCache.end() && (i < toDelet);)
        {
            m_dataCache.erase(beg++);
            i++;
        }
    }
}

void DataCache::addData(ProtoData data) {
    std::lock_guard<std::mutex> lk(m_receiveDataMutex);
    m_receiveData.push_back(std::move(data));
}

void DataCache::addData(std::vector<ProtoData> &data) {
    std::lock_guard<std::mutex> lk(m_receiveDataMutex);
    m_receiveData.reserve(m_receiveData.size() + data.size());
    std::move(data.begin(), data.end(), std::back_inserter(m_receiveData));
}

void DataCache::processData(const ProtoData &data)
{
    double currTime = Util::getMsTime();
    if ((*data.topic).find("encode_srv-EncodeSrv.EncodeJpeg-CAM") != std::string::npos) // 如果是图片topic特殊处理
    {
        // Log_Info("picture topic: {}", *data.topic);
        //  续写数据
        //  ManagerFile::getInstance().writeFile(m_pictureDataCacheThird.data);
        // for (auto tmpPictureMap : m_pictureDataCacheMap)
        // {
        //     Log_Info("picture topic:{},message size;{}", tmpPictureMap.first, sizeof(tmpPictureMap.second));
        // }
        checkPictureDataTimeValid(*data.topic, data);
    }
    else
    {
        // 续写数据
        ManagerFile::getInstance().writeFile(data);

        std::lock_guard<std::mutex> lk(m_mutex);

        // 根据topic插入最新数据，数据以 <time,data>
        m_dataCache.insert({currTime, data});
    }

    // 进行条件判断,由于数据量大，条件判断在单独的线程  (特殊trigger的处理)
    if (AdrTrigger::getInstance().protoRuleContainTopic(*data.topic))
    {
        {
            std::lock_guard<std::mutex> lk(m_mutex);

            // 存入最新一帧数据
            m_lastTopicData[*data.topic] = data;
        }

        AdrTrigger::getInstance().execTriggerEvent(data);
    }

    // 信号解析采集
    if (SignalCollect::getInstance().protoRuleContainTopic(*data.topic))
    {
        SignalCollect::getInstance().push2SigMap(data);
    }
}

void DataCache::dealSentryEvent(TriggerEventInfo &trigger, bool &bIgnore)
{
    std::lock_guard<std::mutex> lk(m_mutex);

    auto iter = m_eventPool.find(IT088_ONE);
    if (iter != m_eventPool.end())
    {
        Log_Info("zjs_tmp_0321;sentry_trig type old: {}  new: {}", iter->second.triggerType, trigger.triggerType);
        if (iter->second.triggerType > trigger.triggerType) // 高 -》低;忽略低
        {
            bIgnore = true;
        }
        else if (iter->second.triggerType < trigger.triggerType) // 低 -》高;停止低录制，开始高录制
        {
            // 担心写文件耗时，所以放到单独线程
            ManagerFile::getInstance().closeFile(iter->second);

            // 结束，防止数据进来又触发
            iter = m_eventPool.erase(iter);
        }
    }
}

// 取出前多少秒的数据存入DAT，后续文件继续存入DAT
void DataCache::acquireDataToSave(TriggerEventInfo &trigger)
{
    std::unique_lock<std::mutex> lk(m_mutex);

    // 不包含，触发trigger存入map
    if (!Contain_Map(m_eventPool, trigger.eventName))
    {
        Log_Info("event happen: {}  start", trigger.eventName);

        // 上次触发事件如果在条件引擎那设置，可能m_eventPool还有这个事件，进不来。得等到m_eventPool消除（下个limit限制进来才happen）
        AdrTrigger::getInstance().settrigLaterTime(trigger.eventName);

        m_eventPool.insert({trigger.eventName, trigger});

        // 触发后，取数据存文件
        getBufferDataToSaveNolock(trigger);
    }
    else
    {
        // 地图采集事件,延时
        if (trigger.eventName == CSMAP_1 || trigger.eventName == CSMAP_2 || trigger.eventName == CSMAP_3 || trigger.eventName == CSMAP_4)
        {
            TriggerEventInfo trig = m_eventPool[trigger.eventName];
            trig.laterTime = trigger.triggerTime - trig.triggerTime + trigger.laterTime;
            if (trigger.otherSysFile.size() != 0)
            {
                trig.otherSysFile = trigger.otherSysFile;
            }
            m_eventPool[trigger.eventName] = trig;
        }

        // 营地哨兵续录功能,延时
        if (trigger.eventName == IT088_ONE || trigger.eventName == "BA015")
        {
            //double currTime = Util::getMsTime();
            //TriggerEventInfo trig = m_eventPool[trigger.eventName];
            double laterTime=0.0;//性能优化，减少创建临时trig带来的开销，直接对容器对象成员值进行修改
            //trig.laterTime = trigger.triggerTime - trig.triggerTime + trigger.laterTime;
            laterTime=trigger.triggerTime - (m_eventPool[trigger.eventName]).triggerTime +trigger.laterTime;
            if (laterTime <= 45 * 1000) // 连续触发以第一次触发事件为准，延续持续时间。若第42s触发了，按要求要录到后5s(第47s),结果最多到45s。后2s没录。
            {
                (m_eventPool[trigger.eventName]).laterTime = laterTime;
                Log_Info("YingDi event : {}  delayed", trigger.eventName);
            }
            else
            {
                laterTime = 45 * 1000;
                (m_eventPool[trigger.eventName]).laterTime = laterTime;
                Log_Info("YingDi event : {}  delayed full 45s;", trigger.eventName);
            }
        }
        else if (TriggerStatus::TS_END == trigger.status)
        {
            TriggerEventInfo startTrig = m_eventPool[trigger.eventName];
            startTrig.triggerTime = trigger.triggerTime; // 更新触发时间
            startTrig.status = TriggerStatus::TS_END;    // 关闭trigger
            m_eventPool[trigger.eventName] = startTrig;
            Log_Info("event endTrigger: {}  end", trigger.eventName);
        }
    }
}

//  围栏超时，结束众包地图事件（事件删除，文件删除）
void DataCache::endEvent(string eventCode)
{
    std::lock_guard<std::mutex> lk(m_mutex);

    auto iter = m_eventPool.find(eventCode);
    if (iter != m_eventPool.end())
    {
        auto &trigger = iter->second;
        ManagerFile::getInstance().closeFile(trigger);
        iter = m_eventPool.erase(iter);
    }
}

// 判断事件是否结束
void DataCache::checkTriggerEventEnd()
{
    std::lock_guard<std::mutex> lk(m_mutex);

    double currTime = Util::getMsTime();
    for (auto iter = m_eventPool.begin(); iter != m_eventPool.end();)
    {
        auto &trigger = iter->second;
        if ((trigger.eventName == IT088_ONE) && (global_data::g_adc_status != ADC_STATUS_SHAOBIN)) // 如果触发录哨塔模式，中途topic_mode不等号4，则退出文件录制
        {
            Log_Info("eventName is IT088,topic_mode:{},closeFile", global_data::g_adc_status);
            ManagerFile::getInstance().closeFile(trigger);
            iter = m_eventPool.erase(iter);
            continue;
        }
        // 判断trigger数据是否满足时长
        //  if (currTime - trigger.triggerTime > trigger.collectDatas.laterTime)
        //  Log_Info("Trigger :{}  ready to save, currTime: {}  before time: {}", trigger.eventName, currTime - trigger.triggerTime, trigger.beforeTime);
        if (TriggerStatus::TS_START == trigger.status)
        {
            if (currTime - trigger.triggerTime > 70 * 1000)
            {
            }
            else // 过程事件开始后一直录，大于70s后就结束；否则不结束跳过判断
            {
                iter++;
                continue;
            }
        }
        //
        if (trigger.eventName == CSMAP_1 || trigger.eventName == CSMAP_3 )
        {
            //当前时间离触发时间没到5分钟，并且也没到后多少秒；认为地图事件没结束;
            if ((currTime - trigger.triggerTime < 5* 60*1000) && (currTime - trigger.triggerTime <= trigger.laterTime))
            {
                iter++;
                continue;
            }            
        }
        else 
        {
            if (currTime - trigger.triggerTime <= trigger.laterTime)
            {
                iter++;
                continue;
            }
            
        }
        // 事件结束，时间满足，结束保存文件
        Log_Info("Trigger end data enough to save name: {}", trigger.eventName);

        // BA015一键紧急录制,添加打包上传标定文件功能
        if (trigger.eventName == "BA015")
        {
            // // 删除目标目录的标定文件
            // CalibrationFile::deleteCalibrationFile();
            // // 读取标定文件
            // uint8_t ret = SoaEnginerringModel::getInstance().getCalibrationFile();
            // // 事件文件上云
            // if (ret)
            // {
            //     SoaEnginerringModel::getInstance().calibrationFileUpload();
            //     Log_Info("[DataCache][checkTriggerEventEnd] BA015 Calibration File upload SUCCESS");
            // }
            // else
            // {
            //     Log_Info("[DataCache][checkTriggerEventEnd] BA015 Calibration File upload ERROR");
            // }
        }

        // 如果是图片topic特殊处理,将第三帧的图片写入 begin
        std::map<std::string, std::vector<ProtoData>> pieceData;
        for (auto &data : m_pictureDataCacheMap)
        {
            std::string topic = data.first;
            if (Contain_List(trigger.collectDatas, topic))
            {
                std::string type = DataRecord::getFileNameType(topic);
                // 第三个数据结构一直是最新的
                if (CompareValueIsZero(data.second.pictureDataCacheThird.time) == false)
                {
                    ManagerFile::getInstance().writeFile(data.second.pictureDataCacheThird.data);
                    // pieceData[type].push_back(data.second.pictureDataCacheSecond.data);
                }
            }
        }

        // 担心写文件耗时，所以放到单独线程
        ManagerFile::getInstance().closeFile(trigger);

        // 结束，防止数据进来又出发
        iter = m_eventPool.erase(iter);
    }
}

void DataCache::getBufferDataToSave(const TriggerEventInfo &trigger) {
    std::lock_guard<std::mutex> lk(m_mutex);
    getBufferDataToSaveNolock(trigger);
}

void DataCache::getBufferDataToSaveNolock(const TriggerEventInfo &trigger) {

    Log_Info("[getBufferDataToSaveNolock] trigger:{} startTime:{},latertime:{},intervening time:{}",trigger.eventName, trigger.,
         trigger.laterTime,trigger.triggerStartTime-trigger.laterTime);
    
    double beforeTime = trigger.triggerTime - trigger.beforeTime;
    //double currTime = Util::getMsTime();
    std::map<std::string, std::vector<ProtoData>> pieceData;
    std::map<std::string, bool> isIframeMap = {
        {ENCODE_SRV_H265_CAM0, false},
        {ENCODE_SRV_H265_CAM1, false},
        {ENCODE_SRV_H265_CAM2, false},
        {ENCODE_SRV_H265_CAM3, false},
        {ENCODE_SRV_H265_CAM4, false},
        {ENCODE_SRV_H265_CAM5, false},
        {ENCODE_SRV_H265_CAM6, false},
        {ENCODE_SRV_H265_CAM7, false},
        {ENCODE_SRV_H265_CAM8, false},
        {ENCODE_SRV_H265_CAM9, false},
        {ENCODE_SRV_H265_CAM10, false},
    };

    // 如果是图片topic特殊处理
    for (auto &data : m_pictureDataCacheMap)
    {
        std::string topic = data.first;
        // for (int i = 0; i < trigger.collectDatas.size(); i++)
        // {
        //     Log_Info("getBufferDataToSave trigger.collectDatas dex:{},trigger.collectDatas:{}", i, trigger.collectDatas[i]);
        // }
        if (Contain_List(trigger.collectDatas, topic))
        {
            std::string type = DataRecord::getFileNameType(topic);
            if (CompareValueIsZero(data.second.pictureDataCacheFirst.time) == false)
            {
                pieceData[type].push_back(data.second.pictureDataCacheFirst.data);
            }
            if (CompareValueIsZero(data.second.pictureDataCacheSecond.time) == false)
            {
                pieceData[type].push_back(data.second.pictureDataCacheSecond.data);
            }
        }
    }

	if(trigger.eventName == IT088_ONE) 
    {
		Log_Info("[DataCache]trigger {} Time:{},utctime:{}",trigger.eventName, trigger.triggerStartTime, trigger.triggerTime);
		Log_Info("[DataCache] {} m_dataCache First frame: Time:{}",trigger.eventName, to_string(m_dataCache.begin()->first));
		Log_Info("[DataCache] {} m_dataCache end frame: Time:{}",trigger.eventName, to_string(m_dataCache.rbegin()->first));
	}

    if(trigger.eventName == "BA844") 
    {
        Log_Info("########################################################################################################################################");
		Log_Info("[DataCache]trigger {} Time:{},utctime:{}",trigger.eventName, trigger.triggerStartTime, trigger.triggerTime);
		Log_Info("[DataCache] {} m_dataCache First frame: Time:{}",trigger.eventName, to_string(m_dataCache.begin()->first));
		Log_Info("[DataCache] {} m_dataCache end frame: Time:{}",trigger.eventName, to_string(m_dataCache.rbegin()->first));
	}


    for (auto &data : m_dataCache)
    {
        // 取出trigger当前时间与前多少秒的时间去存DAT文件
        if (beforeTime <= data.first && ((trigger.triggerTime + 2000) >= data.first)) // triggerTime由trig线程赋值，到这里data_cath线程执行时可能是500ms后了；加上容错2s,补上这500ms期间的数据
        {
            std::string topic = *data.second.topic;
            // Log_Info("data enough to save topic: {}", data.second.topic);
            if (Contain_List(trigger.collectDatas, topic))
            {
                // 法规规定，视频和中间变量和图片需要存储在不同的文件
                std::string type = DataRecord::getFileNameType(topic);
                if (DAT_FILE_TYPE_VIDEO == type)
                {
                    EncodeSrv::EncodeH265 enc;
                    if (!enc.ParsePartialFromString(*(data.second.data)))
                    {
                        Log_Topic("publish Parse EncodeSrv::EncodeH265 failed");
                        continue;
                    }
                    if (JudgeIsIFrame(topic, enc, isIframeMap) == false) // 视频文件罗盘第一帧必须是I帧
                    {
                        Log_Info("is not i frame topic:{},time:{}",*data.second.topic,data.second.timestamp);
                        //continue;
                        if(trigger.eventName == IT088_ONE)
                        {
	                        // 从beforeTime开始往前找（beforeTime 和beforeTime - 2000之间）到第一个I帧
		                    FindVedioFirstIFrame(pieceData, isIframeMap, beforeTime, data.first, topic);
						}
						else
						{
							continue;
						}
                    }
                }

                pieceData[type].push_back(data.second);
            }
        }
    }

    // 收集完视频帧后，打印起始和终止时间
    auto videoIt = pieceData.find(DAT_FILE_TYPE_VIDEO);
    if (videoIt != pieceData.end() && !videoIt->second.empty()) {
        const auto &videoFrames = videoIt->second;
        double firstFrameTime = videoFrames.front().timestamp;  // 采集到的第一帧时间戳
        double lastFrameTime = videoFrames.back().timestamp;    // 采集到的最后一帧时间戳

        Log_Info("{}: Collected video frame time range: [{}ms, {}ms], total {} frames | Trigger event expected range: [{}ms, {}ms]", trigger.eventName,
         firstFrameTime, lastFrameTime, videoFrames.size(),
         beforeTime, trigger.triggerTime + trigger.laterTime);  // 补充预期范围
    }

    // 写文件耗时，所以放到单独线程
    // if (pieceData.size() > 0)
    if(trigger.eventName == IT088_ONE) 
    {
		Log_Info("[DataCache]trigger {} Time:{}",trigger.eventName, trigger.triggerStartTime);
		auto itMap	= pieceData.find(DAT_FILE_TYPE_VIDEO);
		if (itMap != pieceData.end())
		{
			const std::vector<ProtoData>& vectorTop =  itMap->second;
			Log_Info("[DataCache] {} before 15 First frame: Time:{},topic:{}",trigger.eventName, to_string(vectorTop.front().timestamp), *(vectorTop.front().topic));
			Log_Info("[DataCache] {} before 15 end frame: Time:{},topic:{}",trigger.eventName, to_string(vectorTop.back().timestamp), *(vectorTop.back().topic));
		}
	}
    {
        ManagerFile::getInstance().openFile(pieceData, trigger);
    }
}

bool DataCache::JudgeIsIFrame(std::string &topic, EncodeSrv::EncodeH265 &enc, std::map<std::string, bool> &isIframeMap)
{
    // Log_Info("[xiangrui debug] [JudgeIsIFrame] topic:{}", topic);

    if (Contain_Map(isIframeMap, topic))
    {
        if (isIframeMap[topic] == false)
        {
            if (enc.frame_data().size() < 5)
            {
                Log_ERROR("h265Data size <5");
                return false;
            }
            if (CODEC_PROBE_H265_I_FRAME(enc.frame_data().c_str()))
            {
                Log_Info("is I frame,topic:{}", topic);
                isIframeMap[topic] = true;
                return true;
            }
            else
            {
                // Log_Info("is not I frame,topic:{}", topic);
                return false;
            }
        }
        else
        {
            return true;
        }
    }
    else
    {
        Log_Info("Contain_Map(isIframeMap, topic) is false,topic:{}", topic);
        return false;
    }
}

ProtoData DataCache::getLastDataByTopic(const std::string &topic)
{
    std::lock_guard<std::mutex> lk(m_mutex);

    return m_lastTopicData[topic];
}

void DataCache::setTopicDataInvildTime(const std::string &topic, const double &beforTime, const double &afterTime)
{
    ProtoValidTime time;
    time.beforeTime = beforTime;
    time.afterTime = afterTime;

    {
        std::lock_guard<std::mutex> lk(m_mutex);
        m_dataViledTime[topic] = time;
    }
}

// 无须加锁，调用时已经上锁
ProtoValidTime DataCache::getTopicDataInvildTime(const std::string &topic)
{
    if (Contain_Map(m_dataViledTime, topic))
    {
        return m_dataViledTime[topic];
    }
    // 如果没有，默认10秒
    ProtoValidTime time;
    if(global_data::g_work_status==2)
    {
        time.beforeTime = 30000;
    }
    else
    {
        time.beforeTime = 17000;
    }
    time.afterTime = 5000;
    return time;
}


// 从beforeTime开始往前找（beforeTime 和beforeTime - 2000之间）到第一个I帧
void DataCache::FindVedioFirstIFrame(std::map<std::string, std::vector<ProtoData>> &pieceData, 
	std::map<std::string, bool> &isIframeMap, double beforeTime, double endTime, const std::string topicname)
{
	bool foundIFrame = false;
    for (auto it = m_dataCache.rbegin(); it != m_dataCache.rend() && !foundIFrame; ++it)
    {
        if (it->first < beforeTime && it->first >= (beforeTime - 2000))
        {
            std::string subTopic = *it->second.topic;
            if (subTopic == topicname)
            {
                EncodeSrv::EncodeH265 subEnc;
                if (!subEnc.ParsePartialFromString(*(it->second.data)))
                {
                    Log_Topic("publish Parse EncodeSrv::EncodeH265 failed");
                    continue;
                }

                if (JudgeIsIFrame(subTopic, subEnc, isIframeMap))
                {
                    foundIFrame = true;
                    pieceData[DAT_FILE_TYPE_VIDEO].push_back(it->second);
					Log_Info("find first i frame topic:{},time:{}",topicname,it->second.timestamp);
                    // 插入之后的所有P帧                    
					auto nextIt = std::next(it.base());
                    while (nextIt != m_dataCache.end() && nextIt->first <= endTime)
                    {
						std::string topic = *nextIt->second.topic;
						
						if (topic == topicname)
						{
							EncodeSrv::EncodeH265 enc;
							if (!enc.ParsePartialFromString(*(nextIt->second.data)))
							{
								Log_Topic("publish Parse EncodeSrv::EncodeH265 failed");
								nextIt++;
								continue;
							}
							pieceData[DAT_FILE_TYPE_VIDEO].push_back(nextIt->second);
							Log_Info("insert p frame topic:{},time:{}",topicname,nextIt->second.timestamp);
						}
						
						nextIt++;
					}
					//Log_Info("exit:endTime:{},nextIt->first:{}",to_string(endTime),to_string(nextIt->first));
		            break;
                }
            }
        }
    }

    if (!foundIFrame)
    {
        Log_Info("No I-frame found in the specified range.");
    }
}

